from typing import Optional
import tkinter as tk
from tkinter import filedialog

import cv2
import numpy as np
from numpy import ndarray as mat

class CannySelectorTool:
    def __init__(self, windows_width: int = 720, windows_height: int = 640, windows_name: str = "Canny Selector Tool"):
        self.__windows_width: int = windows_width
        self.__windows_height: int = windows_height
        self.__windows_name: str = windows_name
        self.__img_hsv: Optional[mat] = None

    def run_bgr(self, img_bgr):
        img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
        self.run_canny(img_gray)

    def run_canny(self, img_gray):
        self.__img_gray = img_gray
        cv2.namedWindow(self.__windows_name, cv2.WINDOW_NORMAL)
        debug_resize_times = 0.6
        cv2.resizeWindow(self.__windows_name, np.int_(self.__windows_width * debug_resize_times), np.int_(self.__windows_height * debug_resize_times))
        cv2.imshow(self.__windows_name, self.__img_gray)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

    def run_hough_circle(self, img_bgr):
        gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
        gray = cv2.medianBlur(gray, 5)

        cv2.namedWindow('Hough Circle Transform')

        cv2.createTrackbar('dp', 'Hough Circle Transform', 1, 10, self.nothing)
        cv2.createTrackbar('minDist', 'Hough Circle Transform', 20, 1000, self.nothing)
        cv2.createTrackbar('param1', 'Hough Circle Transform', 50, 2000, self.nothing)
        cv2.createTrackbar('param2', 'Hough Circle Transform', 30, 1000, self.nothing)
        cv2.createTrackbar('minRadius', 'Hough Circle Transform', 0, 1000, self.nothing)
        cv2.createTrackbar('maxRadius', 'Hough Circle Transform', 0, 1000, self.nothing)

        while True:
            dp = cv2.getTrackbarPos('dp', 'Hough Circle Transform')
            minDist = cv2.getTrackbarPos('minDist', 'Hough Circle Transform')
            param1 = cv2.getTrackbarPos('param1', 'Hough Circle Transform')
            param2 = cv2.getTrackbarPos('param2', 'Hough Circle Transform')
            minRadius = cv2.getTrackbarPos('minRadius', 'Hough Circle Transform')
            maxRadius = cv2.getTrackbarPos('maxRadius', 'Hough Circle Transform')

            if dp == 0:
                dp = 1

            circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp, minDist,
                                       param1=param1, param2=param2,
                                       minRadius=minRadius, maxRadius=maxRadius)

            output = img_bgr.copy()

            if circles is not None:
                circles = np.uint16(np.around(circles))
                for i in circles[0, :]:
                    cv2.circle(output, (i[0], i[1]), i[2], (0, 255, 0), 2)
                    cv2.circle(output, (i[0], i[1]), 2, (0, 0, 255), 3)

            cv2.imshow('Hough Circle Transform', output)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        cv2.destroyAllWindows()

    def nothing(self, x):
        pass

    def select_file_and_run(self):
        root = tk.Tk()
        root.withdraw()
        file_path = filedialog.askopenfilename(title="Select an image file", filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp")])
        if file_path:
            img_bgr = cv2.imread(file_path)
            img_bgr = cv2.resize(img_bgr, (960, 540))
            if img_bgr is not None:
                self.run_bgr(img_bgr)
                self.run_hough_circle(img_bgr)
            else:
                print("Failed to read the image file.")
        else:
            print("No file selected.")

if __name__ == "__main__":
    tool = CannySelectorTool()
    tool.select_file_and_run()